/* 
 * File:   main.cpp
 * Author: Tung Mai
 *
 * Created on June 15, 2010, 7:33 PM
 */

#include <QuickTime/QuickTime.h>

bool IsQuickTimeInstalled()
{
    long version;
    OSErr result;

    result = Gestalt(gestaltQuickTime, &version);
    
    if (result != noErr)
    {
        printf("QuickTime is not installed.\n");
        return false;
    }

    printf("QuickTime version: %x\n", version);
    if (version >= 0x06408000)
    {
        printf("we have version 6.4 or later\n");
    }
    else
    {
        printf("Need QuickTime version 6.4 or later installed.\n");
        return false;
    }
    
    return true;
}

void ExportMovieToAIFF(SeqGrabComponent theSG, char *path)
{
    printf("Begin convert...\n");
    Handle dataRef = NULL;
    OSType dataRefType;
    DataHandler dataHandler;
    OSErr err;
    CFStringRef filePath = CFStringCreateWithCString(kCFAllocatorDefault,
            path, kCFStringEncodingASCII);

    err = QTNewDataReferenceFromFullPathCFString(filePath, kQTNativeDefaultPathStyle,
        0, &dataRef, &dataRefType);
    if (err != noErr)
    {
        printf("Create data ref when export failed\n");
        return;
    }

    // export the movie into a file
    Movie mov = NULL;
    mov = SGGetMovie(theSG);
    if (!mov)
    {
        printf("Get movie from sg failed\n");
        return;
    }

    err = ConvertMovieToDataRef(mov,        // the movie to convert
                         NULL,               // all tracks in the movie
                         dataRef,           // the output data reference
                         dataRefType,       // the data ref type
                         kQTFileTypeAIFF,   // the output file type
                         FOUR_CHAR_CODE('TVOD'),   // the output file creator
                         0,//createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
                         NULL);              // no specific component
    if (err != noErr)
    {
        printf("Convert to aiff failed\n");
    }

    DisposeMovie(mov);
    DisposeHandle(dataRef);
}

int main(int argc, char** argv)
{
    if (!IsQuickTimeInstalled())
    {
        return EXIT_FAILURE;
    }

    OSErr err;
    SeqGrabComponent theSG = NULL;

    err = OpenADefaultComponent(SeqGrabComponentType, 0, &theSG);
    if (err != noErr)
    {
        printf("Open a default SG failed.\n");
        return EXIT_FAILURE;
    }

    err = SGInitialize(theSG);
    if (err != noErr)
    {
        printf("Initialize SG failed.\n");
        if (theSG)
        {
            CloseComponent(theSG);
            theSG = NULL;
        }
    }

    SGChannel audioChannel = NULL;
    err = SGNewChannel(theSG, SGAudioMediaType, &audioChannel);
    if (err != noErr)
    {
        printf("Create an audio channel for SG failed.\n");
        return -1;
    }

    err = SGSetChannelUsage(audioChannel, seqGrabRecord);
    if (err != noErr)
    {
        printf("Set audio channel usage failed.\n");
        if (audioChannel)
        {
            SGDisposeChannel(theSG, audioChannel);
            audioChannel = NULL;
        }
    }

    err = SGSetMaximumRecordTime(theSG, 5 * 60 /* convert to ticks */);
    if (err != noErr)
    {
        printf("set max record time failed\n");
    }

    AudioStreamBasicDescription outputFormat;

    err = QTGetComponentProperty(audioChannel, kQTPropertyClass_SGAudio,
            kQTSGAudioPropertyID_StreamFormat, sizeof(outputFormat), &outputFormat, NULL);
    if (err == noErr)
    {
        outputFormat.mFormatID = kAudioFormatLinearPCM;//kAudioFormatMPEG4AAC;
        outputFormat.mSampleRate = 22050.0;
        outputFormat.mChannelsPerFrame = 1;
        outputFormat.mBitsPerChannel = 8;
        outputFormat.mBytesPerFrame = outputFormat.mChannelsPerFrame * sizeof(SInt8);
        outputFormat.mBytesPerPacket = outputFormat.mChannelsPerFrame * sizeof(SInt8);
//        outputFormat.mFormatFlags = 0;
        outputFormat.mFramesPerPacket = 1; // Sequence Grabber will fill in the fields we don't know.
        outputFormat.mFormatFlags = kLinearPCMFormatFlagIsBigEndian |
            kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;

        err = QTSetComponentProperty(audioChannel, kQTPropertyClass_SGAudio,
                kQTSGAudioPropertyID_StreamFormat, sizeof(outputFormat), &outputFormat);
        if (err != noErr)
        {
            printf("set component property failed\n");
        }
    }
    else
    {
        printf("Get kQTSGAudioPropertyID_StreamFormat failed\n");
    }

    Handle dataRef = NULL;
    OSType dataRefType = NULL;
//    CFStringRef filePath = CFStringCreateWithCString(kCFAllocatorDefault,
//            "/Users/macos2/Desktop/sgaud.aif", kCFStringEncodingASCII);

    err = QTNewDataReferenceFromFullPathCFString(CFSTR("/Users/macos2/Desktop/sgaud.aifc"), kQTNativeDefaultPathStyle,
            0, &dataRef, &dataRefType);
    if (err != noErr)
    {
        printf("QTNewDataReferenceFromFullPathCFString failed.\n");
        return -1;
    }

    err = SGSetDataRef(theSG, dataRef, dataRefType, seqGrabToDisk);
    if (err != noErr)
    {
        printf("set data ref failed\n");
    }

    DisposeHandle(dataRef);

    err = SGPrepare(theSG, false, true);
    if (err != noErr)
    {
        printf("prepare SG failed\n");
    }

    // Recording
    err = SGStartRecord(theSG);
    if (err != noErr)
    {
        printf("start rec SG failed\n");
    }

    // Setup a timer to drive the sequence grabber. The timer method should call SGIdle(sequenceGrabber)
    while(SGIdle(theSG) == noErr);

    // Stoping
    err = SGStop(theSG); // Stop also the idle timer
    if (err != noErr)
    {
        printf("stop rec SG failed\n");
    }

    err = SGRelease(theSG);
    if (err != noErr)
    {
        printf("release after prepare SG failed\n");
    }

    ExportMovieToAIFF(theSG, "/Users/macos2/Desktop/sgaud.aiff");

    // Cleanup
    SGDisposeChannel(theSG, audioChannel);
    CloseComponent(theSG);
    
    return (EXIT_SUCCESS);
}

